#ifndef H_COctStream_H
#define	H_COctStream_H

#include "ISwapableBuffer.h"
#include "IData.h"
#include "../typedefine.h"
#include "../StringDefine.h"
#include "../VectorDefine.h"
#include "../ListDefine.h"
#include "../SortedMapDefine.h"
#include "../SortedSetDefine.h"
#include "../UnOrderedMapDefine.h"
#include "../UnOrderedSetDefine.h"

namespace QWER
{

	QDLL_EXPORT QCLASS COctStream : public ISwapableBuffer
	{
	public:
		COctStream();
		COctStream(UINT32 dwCapacity);

#ifndef _USING_CLI
		~COctStream();

		void assign(const UINT8* pBegin, const UINT8* pEnd);
#endif
#ifdef _USING_CLI
		void assign(PTR(array<UINT8>) poBuffer, UINT32 dwBegin, UINT32 dwSize);
#else
		void assign(CONST_PTR(UINT8) poBuffer, UINT32 dwBegin, UINT32 dwSize);
#endif

		virtual SReplaceRet ReplaceBuffer(CONST_REF(SReplaceRet) sBuffer);

		void Append(CONST_PTR_OR_REF(COctStream) os)
		{
			CONST_PTR(COctStream) pos = TO_PTR2(os);
			Append(pos->GetBuffer(), 0, pos->Size());
		}

#ifdef _USING_CLI
		void Append(PTR(array<UINT8>) poBuffer, UINT32 dwBegin, UINT32 dwSize);
#else
		void Append(CONST_PTR(UINT8) poBuffer, UINT32 dwBegin, UINT32 dwSize);
#endif
		void Replace(UINT32 dwThisBegin, CONST_PTR_OR_REF(COctStream) os)
		{
			CONST_PTR(COctStream) pos = TO_PTR2(os);
			Replace(dwThisBegin, pos->GetBuffer(), 0, pos->Size());
		}

#ifdef _USING_CLI
		void Replace(UINT32 dwThisBegin, PTR(array<UINT8>) poBuffer, UINT32 dwBufferBegin, UINT32 dwSize);
#else
		void Replace(UINT32 dwThisBegin, CONST_PTR(UINT8) poBuffer, UINT32 dwBufferBegin, UINT32 dwSize);
#endif

		inline UINT32 GetLeftUnMarshalSize() QCONST_FUNC 
		{
			return Size() - m_dwUnmarIndex;
		}

		inline UINT32 GetUnmarIndex() QCONST_FUNC { return m_dwUnmarIndex; }
		inline void SetUnmarIndex(UINT32 dwIndex)
		{
			m_dwUnmarIndex = dwIndex;
		}
		inline void ResetUnmarIndex()
		{
			m_dwUnmarIndex = 0;
		}

		inline UINT32 Size() QCONST_FUNC
		{
			return m_dwSize;
		}

		inline void Clear()
		{
			m_dwSize = 0;
			m_dwUnmarIndex = 0;
		}

		inline UINT32 size() QCONST_FUNC
		{
			return Size();
		}

		inline void clear()
		{
			Clear();
		}

		inline UINT32 Capacity() QCONST_FUNC
		{
#ifdef _USING_CLI
			return m_aData == NULL_PTR ? 0 : (UINT32)m_aData->Length;
#else
			return m_dwCapacity;
#endif
		}

		inline UINT32 capacity() QCONST_FUNC
		{
			return Capacity();
		}

		void Reserve(UINT32 dwCapacity);

		inline void reserve(UINT32 dwCapacity)
		{
			Reserve(dwCapacity);
		}

		inline void Resize(UINT32 dwSize)
		{
			Reserve(dwSize);
			m_dwSize = dwSize;
		}

		inline void resize(UINT32 dwSize)
		{
			Resize(dwSize);
		}

#ifdef _USING_CLI
		inline PTR(array<UINT8>) GetBuffer()
		{
			return m_aData;
		}
#else
		inline PTR(UINT8) GetBuffer()
		{
			return m_aData;
		}
		inline CONST_PTR(UINT8) GetBuffer() const
		{
			return m_aData;
		}
#endif

		void CloneTo(PTR_OR_REF(COctStream) roOctStream) QCONST_FUNC;

		inline PTR_OR_REF(COctStream) Push(CONST_PTR_OR_REF(IData) roData)
		{
			TO_PTR2(roData)->_Marshal(TO_REF2(this));
			return TO_REF2(this);
		}

		inline PTR_OR_REF(COctStream) Pop(PTR_OR_REF(IData) roData)
		{
			TO_PTR2(roData)->_UnMarshal(TO_REF2(this));
			return TO_REF2(this);
		}

		inline PTR_OR_REF(COctStream) Push(INT8 btData)
		{
			_PushBack((UINT8)btData);
			return TO_REF2(this);
		}
		inline PTR_OR_REF(COctStream) Push(UINT8 btData)
		{
			_PushBack(btData);
			return TO_REF2(this);
		}

		inline PTR_OR_REF(COctStream) VersionPush(INT8 btData)
		{
			return Push(btData);
		}
		inline PTR_OR_REF(COctStream) VersionPop(REF(INT8) btData)
		{
			return Pop(btData);
		}

		inline PTR_OR_REF(COctStream) VersionPush(UINT8 btData)
		{
			return Push(btData);
		}
		inline PTR_OR_REF(COctStream) VersionPop(REF(UINT8) btData)
		{
			return Pop(btData);
		}

		inline PTR_OR_REF(COctStream) Push(INT16 wData)
		{
			return Push((UINT16)wData);
		}
		inline PTR_OR_REF(COctStream) Push(UINT16 wData)
		{
			_PushBack((UINT8)(wData & 0xFF));
			_PushBack((UINT8)((wData >> 8) & 0xFF));
			return TO_REF2(this);
		}

		inline PTR_OR_REF(COctStream) Push(INT32 dwData)
		{
			return Push((UINT32)dwData);
		}
		inline PTR_OR_REF(COctStream) Push(UINT32 dwData)
		{
			_PushBack((UINT8)(dwData & 0xFF));
			_PushBack((UINT8)((dwData >> 8) & 0xFF));
			_PushBack((UINT8)((dwData >> 16) & 0xFF));
			_PushBack((UINT8)((dwData >> 24) & 0xFF));
			return TO_REF2(this);
		}

		inline PTR_OR_REF(COctStream) Push(INT64 qwData)
		{
			return Push((UINT64)qwData);
		}
		inline PTR_OR_REF(COctStream) Push(UINT64 qwData)
		{
			_PushBack((UINT8)(qwData & 0xFF));
			_PushBack((UINT8)((qwData >> 8) & 0xFF));
			_PushBack((UINT8)((qwData >> 16) & 0xFF));
			_PushBack((UINT8)((qwData >> 24) & 0xFF));
			_PushBack((UINT8)((qwData >> 32) & 0xFF));
			_PushBack((UINT8)((qwData >> 40) & 0xFF));
			_PushBack((UINT8)((qwData >> 48) & 0xFF));
			_PushBack((UINT8)((qwData >> 56) & 0xFF));
			return TO_REF2(this);
		}

		inline PTR_OR_REF(COctStream) Pop(REF(INT8) btData)
		{
#ifdef _OCT_EXCEPTION
			if(GetLeftUnMarshalSize() == 0)
				throw std::out_of_range("");
#endif
			btData = m_aData[m_dwUnmarIndex++];
			return TO_REF2(this);
		}
		inline PTR_OR_REF(COctStream) Pop(REF(UINT8) btData)
		{
#ifdef _OCT_EXCEPTION
			if(GetLeftUnMarshalSize() == 0)
				throw std::out_of_range("");
#endif
			btData = (UINT8)m_aData[m_dwUnmarIndex++];
			return TO_REF2(this);
		}
		inline PTR_OR_REF(COctStream) Pop(REF(INT16) wData)
		{
#ifdef _OCT_EXCEPTION
			if(GetLeftUnMarshalSize() < SIZE_OF_INT16)
				throw std::out_of_range("");
#endif
			wData = (INT16)((UINT16)m_aData[m_dwUnmarIndex] | 
				((UINT16)m_aData[m_dwUnmarIndex + 1] << 8));
			m_dwUnmarIndex += 2;
			return TO_REF2(this);
		}
		inline PTR_OR_REF(COctStream) Pop(REF(UINT16) wData)
		{
#ifdef _OCT_EXCEPTION
			if(GetLeftUnMarshalSize() < SIZE_OF_UINT16)
				throw std::out_of_range("");
#endif
			wData = (UINT16)m_aData[m_dwUnmarIndex] | 
				((UINT16)m_aData[m_dwUnmarIndex + 1] << 8);
			m_dwUnmarIndex += 2;
			return TO_REF2(this);
		}
		inline PTR_OR_REF(COctStream) Pop(REF(INT32) dwData)
		{
#ifdef _OCT_EXCEPTION
			if(GetLeftUnMarshalSize() < SIZE_OF_INT32)
				throw std::out_of_range("");
#endif
			dwData = (INT32)((UINT32)m_aData[m_dwUnmarIndex] | 
				((UINT32)m_aData[m_dwUnmarIndex + 1] << 8) |
				((UINT32)m_aData[m_dwUnmarIndex + 2] << 16) |
				((UINT32)m_aData[m_dwUnmarIndex + 3] << 24));
			m_dwUnmarIndex += 4;
			return TO_REF2(this);
		}
		inline PTR_OR_REF(COctStream) Pop(REF(UINT32) dwData)
		{
#ifdef _OCT_EXCEPTION
			if(GetLeftUnMarshalSize() < SIZE_OF_UINT32)
				throw std::out_of_range("");
#endif
			dwData = (UINT32)m_aData[m_dwUnmarIndex] | 
				((UINT32)m_aData[m_dwUnmarIndex + 1] << 8) |
				((UINT32)m_aData[m_dwUnmarIndex + 2] << 16) |
				((UINT32)m_aData[m_dwUnmarIndex + 3] << 24);
			m_dwUnmarIndex += 4;
			return TO_REF2(this);
		}
		inline PTR_OR_REF(COctStream) Pop(REF(INT64) qwData)
		{
#ifdef _OCT_EXCEPTION
			if(GetLeftUnMarshalSize() < SIZE_OF_INT64)
				throw std::out_of_range("");
#endif
			qwData = (INT64)((UINT64)m_aData[m_dwUnmarIndex] | 
				((UINT64)m_aData[m_dwUnmarIndex + 1] << 8) |
				((UINT64)m_aData[m_dwUnmarIndex + 2] << 16) |
				((UINT64)m_aData[m_dwUnmarIndex + 3] << 24) |
				((UINT64)m_aData[m_dwUnmarIndex + 4] << 32) |
				((UINT64)m_aData[m_dwUnmarIndex + 5] << 40) |
				((UINT64)m_aData[m_dwUnmarIndex + 6] << 48) |
				((UINT64)m_aData[m_dwUnmarIndex + 7] << 56));
			m_dwUnmarIndex += 8;
			return TO_REF2(this);
		}
		inline PTR_OR_REF(COctStream) Pop(REF(UINT64) qwData)
		{
#ifdef _OCT_EXCEPTION
			if(GetLeftUnMarshalSize() < SIZE_OF_UINT64)
				throw std::out_of_range("");
#endif
			qwData = (UINT64)m_aData[m_dwUnmarIndex] | 
				((UINT64)m_aData[m_dwUnmarIndex + 1] << 8) |
				((UINT64)m_aData[m_dwUnmarIndex + 2] << 16) |
				((UINT64)m_aData[m_dwUnmarIndex + 3] << 24) |
				((UINT64)m_aData[m_dwUnmarIndex + 4] << 32) |
				((UINT64)m_aData[m_dwUnmarIndex + 5] << 40) |
				((UINT64)m_aData[m_dwUnmarIndex + 6] << 48) |
				((UINT64)m_aData[m_dwUnmarIndex + 7] << 56);
			m_dwUnmarIndex += 8;
			return TO_REF2(this);
		}

		inline PTR_OR_REF(COctStream) Push (BOOLN val)
		{
#ifdef _USING_CLI
			return Push(val ? (UINT8)1 : (UINT8)0);
#else
			return Push ((UINT8)val);
#endif
		}

		inline PTR_OR_REF(COctStream) Pop (REF(BOOLN) val)
		{
			UINT8 btVal = 0;
			Pop (btVal);
			val = (btVal != 0);
			return TO_REF2(this);
		}

#ifdef _USING_CLI
		inline PTR_OR_REF(COctStream) Push (float val)
		{
			array<UINT8>^ aVal = System::BitConverter::GetBytes(val);
			for(int i = 0; i != aVal->Length; i++)
				_PushBack(aVal[i]);
			return this;
		}

		inline PTR_OR_REF(COctStream) Pop (REF(float) val)
		{
			val =  System::BitConverter::ToSingle(m_aData, (int)m_dwUnmarIndex);
			m_dwUnmarIndex += SIZE_OF_FLOAT;
			return this;
		}

		inline PTR_OR_REF(COctStream) Push (double val)
		{
			array<UINT8>^ aVal = System::BitConverter::GetBytes(val);
			for(int i = 0; i != aVal->Length; i++)
				_PushBack(aVal[i]);
			return this;
		}

		inline PTR_OR_REF(COctStream) Pop (REF(double) val)
		{
			val =  System::BitConverter::ToDouble(m_aData, (int)m_dwUnmarIndex);
			m_dwUnmarIndex += SIZE_OF_DOUBLE;
			return this;
		}
#else
		inline PTR_OR_REF(COctStream) Push (float val)
		{
			resize(size() + sizeof(float));
			memcpy(&(m_aData[size() - sizeof(float)]), (UINT8*)&val, sizeof(float));
			//m_oData.insert(m_oData.end(), (UINT8*)&val, ((UINT8*)&val) + sizeof(float));
			return TO_REF2(this);
		}

		inline PTR_OR_REF(COctStream) Pop (REF(float) val)
		{
#ifdef _OCT_EXCEPTION
			if(GetLeftUnMarshalSize() < SIZE_OF_FLOAT)
				throw std::out_of_range("");
#endif
			val = *((float*)(&(*this)[m_dwUnmarIndex]));
			m_dwUnmarIndex += sizeof(float);
			return TO_REF2(this);
		}

		inline PTR_OR_REF(COctStream) Push (double val)
		{
			resize(size() + sizeof(double));
			memcpy(&(m_aData[size() - sizeof(double)]), (UINT8*)&val, sizeof(double));
			//m_oData.insert(m_oData.end(), (UINT8*)&val, ((UINT8*)&val) + sizeof(float));
			return TO_REF2(this);
		}

		inline PTR_OR_REF(COctStream) Pop (REF(double) val)
		{
#ifdef _OCT_EXCEPTION
			if(GetLeftUnMarshalSize() < SIZE_OF_DOUBLE)
				throw std::out_of_range("");
#endif
			val = *((double*)(&(*this)[m_dwUnmarIndex]));
			m_dwUnmarIndex += sizeof(double);
			return TO_REF2(this);
		}
#endif

		inline PTR_OR_REF(COctStream) Push(CONST_PTR_OR_REF(COctStream) ros)
		{
			CONST_PTR(COctStream) pos = TO_PTR2(ros);
			UINT32 dwOsSize = pos->size();
			Push(dwOsSize);
			if (dwOsSize != 0)
			{
				UINT32 dwSize = size();
				resize(dwSize + dwOsSize);
#ifdef _USING_CLI
				array<UINT8>::Copy(pos->m_aData, 0, m_aData, (INT32)dwSize, (INT32)dwOsSize);
#else
				memcpy(&(m_aData[dwSize]), pos->m_aData, dwOsSize);
#endif
			}
			return TO_REF2(this);
		}

		inline PTR_OR_REF(COctStream) Pop(PTR_OR_REF(COctStream) ros)
		{
			PTR(COctStream) pos = TO_PTR2(ros);
			pos->clear();
			UINT32 dwOsSize = 0;
			Pop(dwOsSize);
			if (dwOsSize != 0)
			{
				pos->assign(m_aData, m_dwUnmarIndex, dwOsSize);
			}
			return TO_REF2(this);
		}

		PTR_OR_REF(COctStream) Push(
#ifdef _USING_CLI
			CString roData
#else
			CONST_REF(CString) roData
#endif
			);

		PTR_OR_REF(COctStream) Pop(REF(CString) roData);

#ifndef _USING_CLI
		CONST_REF(UINT8) operator[](UINT32 dwIndex) QCONST_FUNC
		{
			if(dwIndex >= m_dwSize)
				throw QNEW std::out_of_range("");
			return m_aData[dwIndex];
		}

		REF(UINT8) operator[](UINT32 dwIndex)
		{
			if(dwIndex >= m_dwSize)
				throw QNEW std::out_of_range("");
			return m_aData[dwIndex];
		}
#else
		property UINT8 default[UINT32]
		{
			UINT8 get(UINT32 index)
			{
				if(index >= m_dwSize)
					throw QNEW System::ArgumentOutOfRangeException();
				return m_aData[index];
			}
			void set(UINT32 index, UINT8 value)
			{
				if(index >= m_dwSize)
					throw QNEW System::ArgumentOutOfRangeException();
				m_aData[index] = value;
			}
		}
#endif

#ifdef _USING_CLI
#else
		inline COctStream& operator<<(const IData& roData)
		{
			return Push(roData);
		}

		inline COctStream& operator>>(IData& roData)
		{
			return Pop(roData);
		}

		inline COctStream& operator<<(INT8 btData)
		{
			return Push(btData);
		}
		inline COctStream& operator<<(UINT8 btData)
		{
			return Push(btData);
		}

		inline COctStream& operator<<(INT16 wData)
		{
			return Push(wData);
		}
		inline COctStream& operator<<(UINT16 wData)
		{
			return Push(wData);
		}

		inline COctStream& operator<<(INT32 dwData)
		{
			return Push(dwData);
		}
		inline COctStream& operator<<(UINT32 dwData)
		{
			return Push(dwData);
		}

		inline COctStream& operator<<(INT64 qwData)
		{
			return Push(qwData);
		}
		inline COctStream& operator<<(UINT64 qwData)
		{
			return Push(qwData);
		}

		inline COctStream& operator>>(INT8& btData)
		{
			return Pop(btData);
		}
		inline COctStream& operator>>(UINT8& btData)
		{
			return Pop(btData);
		}
		inline COctStream& operator>>(INT16& wData)
		{
			return Pop(wData);
		}
		inline COctStream& operator>>(UINT16& wData)
		{
			return Pop(wData);
		}
		inline COctStream& operator>>(INT32& dwData)
		{
			return Pop(dwData);
		}
		inline COctStream& operator>>(UINT32& dwData)
		{
			return Pop(dwData);
		}
		inline COctStream& operator>>(INT64& qwData)
		{
			return Pop(qwData);
		}
		inline COctStream& operator>>(UINT64& qwData)
		{
			return Pop(qwData);
		}

		inline COctStream& operator << (BOOLN val)
		{
			return Push(val);
		}

		inline COctStream& operator >> (BOOLN& val)
		{
			return Pop(val);
		}

		inline COctStream& operator << (float val)
		{
			return Push(val);
		}

		inline COctStream& operator >> (float& val)
		{
			return Pop(val);
		}

		inline COctStream& operator << (double val)
		{
			return Push(val);
		}

		inline COctStream& operator >> (double& val)
		{
			return Pop(val);
		}

		inline COctStream& operator<<(const std::string& roData)
		{
			return Push(roData);
		}

		inline COctStream& operator>>(std::string& roData)
		{
			return Pop(roData);
		}

		inline COctStream& operator<<(const COctStream& ros)
		{
			return Push(ros);
		}
		inline COctStream& operator>>(COctStream& ros)
		{
			return Pop(ros);
		}

		template<typename T>
		COctStream& operator<<(const std::vector<T>& roData)
		{
			(*this) << (UINT32)(roData.size());
			for(UINT32 i = 0; i != roData.size(); i++)
				(*this) << roData[i];
			return *this;
		}

		template<typename T>
		COctStream& operator>>(std::vector<T>& roData)
		{
			roData.clear();
			UINT32 dwSize;
			(*this) >> dwSize;
			roData.resize(dwSize);
			for(UINT32 i = 0; i != dwSize; i++)
				(*this) >> roData[i];
			return *this;
		}

		template<typename T>
		COctStream& operator+=(const std::vector<T>& val)
		{
			(*this) << (UINT32)(val.size());
			for(UINT32 i = 0; i != val.size(); i++)
				(*this) += (val[i]);
			return *this;
		}
		template<typename T>
		COctStream& operator-=(std::vector<T>& roData)
		{
			roData.clear();
			UINT32 dwSize;
			(*this) >> dwSize;
			roData.resize(dwSize);
			for(UINT32 i = 0; i != dwSize; i++)
				(*this) -= (roData[i]);
			return *this;
		}

		template<typename T>
		COctStream& operator<<(const std::list<T>& roData)
		{
			(*this) << (UINT32)(roData.size());
			for(typename std::list<T>::const_iterator it = roData.begin(); it != roData.end(); it++)
				(*this) << (*it);
			return *this;
		}

		template<typename T>
		COctStream& operator>>(std::list<T>& roData)
		{
			roData.clear();
			UINT32 dwSize;
			(*this) >> dwSize;
			T oData;
			for(UINT32 i = 0; i != dwSize; i++)
			{
				(*this) >> oData;
				roData._PushBack(oData);
			}
			return *this;
		}

		template<typename T>
		COctStream& operator+=(const std::list<T>& roData)
		{
			(*this) << (UINT32)(roData.size());
			for(typename std::list<T>::const_iterator it = roData.begin(); it != roData.end(); it++)
				(*this) += (*it);
			return *this;
		}
		template<typename T>
		COctStream& operator-=(std::list<T>& roData)
		{
			roData.clear();
			UINT32 dwSize;
			(*this) >> dwSize;
			for(UINT32 i = 0; i != dwSize; i++)
			{
				roData._PushBack(T());
				(*this) -= (roData.back());
			}
			return *this;
		}

		template<typename T>
		COctStream& operator<<(const std::set<T>& roData)
		{
			(*this) << (UINT32)(roData.size());
			for(typename std::set<T>::const_iterator it = roData.begin(); it != roData.end(); it++)
				(*this) << (*it);
			return *this;
		}

		template<typename T>
		COctStream& operator>>(std::set<T>& roData)
		{
			roData.clear();
			UINT32 dwSize;
			(*this) >> dwSize;
			T oData = T();
			for(UINT32 i = 0; i != dwSize; i++)
			{
				(*this) >> oData;
				roData.insert(oData);
			}
			return *this;
		}

		template<typename T>
		COctStream& operator+=(const std::set<T>& roData)
		{
			(*this) << (UINT32)(roData.size());
			for(typename std::set<T>::const_iterator it = roData.begin(); it != roData.end(); it++)
				(*this) += (*it);
			return *this;
		}
		template<typename T>
		COctStream& operator-=(std::set<T>& roData)
		{
			roData.clear();
			UINT32 dwSize;
			(*this) >> dwSize;
			T oData = T();
			for(UINT32 i = 0; i != dwSize; i++)
			{
				(*this) -= (oData);
				roData.insert(oData);
			}
			return *this;
		}

		template<typename T>
		COctStream& operator<<(const CUnOrderedSet(T)& roData)
		{
			(*this) << (UINT32)(roData.size());
			for(typename CUnOrderedSet(T)::const_iterator it = roData.begin(); it != roData.end(); it++)
				(*this) << (*it);
			return *this;
		}

		template<typename T>
		COctStream& operator>>(CUnOrderedSet(T)& roData)
		{
			roData.clear();
			UINT32 dwSize;
			(*this) >> dwSize;
			T oData = T();
			for(UINT32 i = 0; i != dwSize; i++)
			{
				(*this) >> oData;
				roData.insert(oData);
			}
			return *this;
		}

		template<typename T>
		COctStream& operator+=(const CUnOrderedSet(T)& roData)
		{
			(*this) << (UINT32)(roData.size());
			for(typename CUnOrderedSet(T)::const_iterator it = roData.begin(); it != roData.end(); it++)
				(*this) += (*it);
			return *this;
		}
		template<typename T>
		COctStream& operator-=(CUnOrderedSet(T)& roData)
		{
			roData.clear();
			UINT32 dwSize;
			(*this) >> dwSize;
			T oData = T();
			for(UINT32 i = 0; i != dwSize; i++)
			{
				(*this) -= (oData);
				roData.insert(oData);
			}
			return *this;
		}

		template<typename T, typename P>
		inline COctStream& operator<<(const std::pair<T, P>& roData)
		{
			(*this) << roData.first;
			(*this) << roData.second;
			return *this;
		}

		template<typename T, typename P>
		inline COctStream& operator>>(std::pair<T, P>& roData)
		{
			(*this) >> roData.first;
			(*this) >> roData.second;
			return *this;
		}

		template<typename T, typename P>
		COctStream& operator+=(const std::pair<T, P>& roData)
		{
			(*this) += roData.first;
			(*this) += roData.second;
			return *this;
		}
		template<typename T, typename P>
		COctStream& operator-=(std::pair<T, P>& roData)
		{
			(*this) -= roData.first;
			(*this) -= roData.second;
			return *this;
		}

		template<typename T, typename P>
		COctStream& operator<<(const std::map<T, P>& roData)
		{
			(*this) << (UINT32)(roData.size());
			for(typename std::map<T, P>::const_iterator it = roData.begin(); it != roData.end(); it++)
				(*this) << (*it);
			return *this;
		}

		template<typename T, typename P>
		COctStream& operator>>(std::map<T, P>& roData)
		{
			roData.clear();
			UINT32 dwSize;
			(*this) >> dwSize;
			typename std::pair<T, P> oData;
			for(UINT32 i = 0; i != dwSize; i++)
			{
				(*this) >> oData;
				roData.insert(oData);
			}
			return *this;
		}

		template<typename T, typename P>
		COctStream& operator+=(const std::map<T, P>& roData)
		{
			(*this) << (UINT32)(roData.size());
			for(typename std::map<T, P>::const_iterator it = roData.begin(); it != roData.end(); it++)
				(*this) += (*it);
			return *this;
		}

		template<typename T, typename P>
		COctStream& operator-=(std::map<T, P>& roData)
		{
			roData.clear();
			UINT32 dwSize;
			(*this) >> dwSize;
			typename std::pair<T, P> oData;
			for(UINT32 i = 0; i != dwSize; i++)
			{
				(*this) -= (oData);
				roData.insert(oData);
			}
			return *this;
		}

		template<typename T, typename P>
		COctStream& operator<<(const CUnOrderedMap(T, P)& roData)
		{
			(*this) << (UINT32)(roData.size());
			for(typename CUnOrderedMap(T, P)::const_iterator it = roData.begin(); it != roData.end(); it++)
				(*this) << (*it);
			return *this;
		}

		template<typename T, typename P>
		COctStream& operator>>(CUnOrderedMap(T, P)& roData)
		{
			roData.clear();
			UINT32 dwSize;
			(*this) >> dwSize;
			typename SPair(T, P) oData;
			for(UINT32 i = 0; i != dwSize; i++)
			{
				(*this) >> oData;
				roData.insert(oData);
			}
			return *this;
		}

		template<typename T, typename P>
		COctStream& operator+=(const CUnOrderedMap(T, P)& roData)
		{
			(*this) << (UINT32)(roData.size());
			for(typename CUnOrderedMap(T, P)::const_iterator it = roData.begin(); it != roData.end(); it++)
				(*this) += (*it);
			return *this;
		}
		template<typename T, typename P>
		COctStream& operator-=(CUnOrderedMap(T, P)& roData)
		{
			roData.clear();
			UINT32 dwSize;
			(*this) >> dwSize;
			typename SPair(T, P) oData;
			for(UINT32 i = 0; i != dwSize; i++)
			{
				(*this) -= (oData);
				roData.insert(oData);
			}
			return *this;
		}

		inline BOOLN operator==(const COctStream& roArg2) const
		{
			return m_dwSize == roArg2.m_dwSize && memcmp(m_aData, roArg2.m_aData, m_dwSize) == 0;
		}
		inline BOOLN operator!=(const COctStream& roArg2) const
		{
			return !operator==(roArg2);
		}
#endif
		inline void Swap(PTR(COctStream) poArg)
		{
#ifdef _USING_CLI
			array<UINT8>^ aTmp = poArg->m_aData;
			poArg->m_aData = m_aData;
			m_aData = aTmp;
#else
			UINT8* aTmp = poArg->m_aData;
			poArg->m_aData = m_aData;
			m_aData = aTmp;

			UINT32 dwTmp1 = poArg->m_dwCapacity;
			poArg->m_dwCapacity = m_dwCapacity;
			m_dwCapacity = dwTmp1;
#endif

			UINT32 dwTmp = poArg->m_dwUnmarIndex;
			poArg->m_dwUnmarIndex = m_dwUnmarIndex;
			m_dwUnmarIndex = dwTmp;

			dwTmp = poArg->m_dwSize;
			poArg->m_dwSize = m_dwSize;
			m_dwSize = dwTmp;
		}

	private:
		inline void _PushBack(UINT8 btD)
		{
			UINT32 dwCapacity = Capacity();
			if (m_dwSize == dwCapacity)
			{
				Reserve(dwCapacity == 0 ? 256 : 2 * dwCapacity);
			}
			m_aData[m_dwSize++] = btD;
		}

	protected:
#ifdef _USING_CLI
		array<UINT8>^ m_aData;
#else
		UINT8* m_aData;
		UINT32 m_dwCapacity;
#endif
		UINT32 m_dwUnmarIndex;
		UINT32 m_dwSize;
	};
};

#endif	/* COCTSTREAM_H */

